import { Component } from 'react';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/lib/locale/zh_CN';
import { TResource } from '@gf-tech/types';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Log } from '@gf-tech/utils';

type TProps = {
    base: string;
    router: TResource;
};

type TState = {
    component: any;
};

class AsyncComponent extends Component<TProps, TState> {
    constructor(props: TProps) {
        super(props);
        this.state = {
            component: null,
        };
    }

    componentDidMount() {
        this.loadModule();
    }

    shouldComponentUpdate(nextProps: TProps) {
        return nextProps.router.pid === this.props.router.pid;
    }

    componentDidUpdate(prevProps: TProps) {
        if (prevProps.router.uriRoute !== this.props.router.uriRoute) {
            this.loadModule();
        }
    }

    async loadModule() {
        try {
            const { base, router } = this.props;
            const res = await import(
                `/src/pages${base + router.uriRoute}/index.tsx`
            );
            this.setState({ component: res.default });
        } catch (err) {
            Log.error(err);
        }
    }

    render() {
        if (this.state.component) {
            return (
                <this.state.component
                    {...this.props}
                    router={this.props.router}
                ></this.state.component>
            );
        } else {
            return null;
        }
    }
}

export class ChildRoutes extends Component<TProps, TProps> {
    render() {
        const { base = '', router } = this.props;
        const routers = router?.childList || [];
        const first = routers.find(it => it.type === 1);
        const redirect = first ? first.uriRoute.replace(/^\//, '') : '';
        /* 
        多层嵌套路由更新时：
            子路由触发更新如果父级已经被更新/销毁，
            子路由的匹配规则依然会生效，特别是重定向时就会产生意料之外的错误
            所以当base为空时（根路由）或者保证路由路径完全后匹配base才进行渲染
            即base不为空且不后匹配时不渲染
        */
        if (base && !new RegExp(router.uriRoute + '$').test(base)) {
            return null;
        }
        return (
            <Routes>
                {routers.map(item => {
                    let path = item.uriRoute.replace(/^\//, '') + '/*';
                    return (
                        <Route
                            path={path}
                            key={item.identified}
                            element={
                                <AsyncComponent base={base} router={item} />
                            }
                        ></Route>
                    );
                })}
                {redirect ? (
                    <Route
                        path='*'
                        element={<Navigate replace to={redirect}></Navigate>}
                    ></Route>
                ) : null}
            </Routes>
        );
    }
}

export class RootRouter extends Component<TProps> {
    render() {
        return (
            <BrowserRouter basename={this.props.base}>
                <ConfigProvider locale={zhCN}>
                    <ChildRoutes base='' router={this.props.router} />
                </ConfigProvider>
            </BrowserRouter>
        );
    }
}
